package rollercoaster.railway.tests;

import java.awt.List;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import rollercoaster.commons.FixedStepTessellation;
import rollercoaster.commons.HomogeneousTextureCoordinatesEvaluator;
import rollercoaster.commons.Node;
import rollercoaster.commons.Vertex3D;
import rollercoaster.commons.interfaces.ITrajectory;
import rollercoaster.commons.interfaces.NodoProducer;
import rollercoaster.environment.utils.Shader;
import rollercoaster.railway.ClassicRailProducer;
import rollercoaster.railway.MagneticRailProducer;
import rollercoaster.railway.XMLBinarioDataReader;
import rollercoaster.railway.utils.ArrayUtils;
import rollercoaster.railway.utils.OBJFileVertexReader;
import rollercoaster.railway.utils.VertexUtils;
import rollercoaster.train.BorderTextureCoordinateEvaluator;
import rollercoaster.train.ClassicCoachProducer;
import rollercoaster.train.interfaces.IMultipleSurfaceControlPointsReader;
import rollercoaster.train.interfaces.VagoneDataReader;
import rollercoaster.train.utils.OBJControlPointsMultipleSurfacesReader;
import rollercoaster.train.utils.XMLVagoneDataReader;

import com.jogamp.opengl.util.FPSAnimator;

public class MagneticRailProducerTest {

	public static void main(String[] args) {
		JFrame frame=new JFrame();
		
		frame.setSize(1400,1400);
		frame.setTitle("Hello Universe");

		GraphicsListener listener=new GraphicsListener();
		GLProfile profile=GLProfile.getGL2ES2();
		GLCanvas canvas = new GLCanvas(new GLCapabilities(profile));
		canvas.addGLEventListener(listener);
		frame.getContentPane().add(canvas);
		canvas.addKeyListener(listener);
		frame.addKeyListener(listener);
		FPSAnimator an = new FPSAnimator(canvas,60);
		an.start();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
public static class GraphicsListener implements GLEventListener, KeyListener{
	/*	
	private static String vertexShader="" +
			"uniform mat4 transform;" +
			"attribute vec3 position;" +
			"attribute vec3 normal;" +
			"varying float light;" +
			"void main(){" +
			"	gl_Position=transform*vec4(position,1);" +
			"	light=dot(normal,vec3(0,0.6,0))+0.4;" +
			"}";
			*/
	
	private static final float distanceRuoteVagon=1.6f;
	private Vertex3D distanceRailTubes;
	
	private static String vertexShader="" +
			"uniform mat4 transform;" +
			"uniform mat2 textureTransform;"+
			"attribute vec3 position;" +
			"attribute vec3 normal;" +
			"attribute vec2 texcoord;"+
			"varying float light;" +
			"varying vec2 ftexcoord;"+
			"void main(){" +
			"	gl_Position=transform*vec4(position,1);" +
			"	vec3 normalVector=(transform*vec4(normal,0)).xyz;" +
			"	normalVector=normalize(normalVector);" +
			"	light=dot(normalVector,vec3(0.0,0.6,0.0))+0.8;" +
			"	ftexcoord=textureTransform*texcoord;"+
			"}";
	
		//texture2D(uSampler, vec2(ftexcoord.s, ftexcoord.t))+
		//+color*vec4(vec3(light),1);
		private static String fragmentShader="" +
				"uniform vec4 color;" +
				"uniform sampler2D uSampler;"+
				"varying float light;" +
				"varying vec2 ftexcoord;"+
				"void main(){" +
				"	gl_FragColor=texture2D(uSampler, vec2(ftexcoord.s, ftexcoord.t))*vec4(vec3(light),1)*color;" +
				"}";
				
		private Shader shader;
		private int attribObject;
		private int normalsAttribObject;
		private int textureAttribObject;
		private int uniformColor;
		private int uniformTransform;
		private int textureTransform;

		private Node nodo;
		private Node nodo2;
		private Node nodo3;
		
		private ITrajectory railTraj;
		
		private float t=0;
		private float t1=0;
		private float tt=0;
		
		private HashMap<Integer, Integer> speedMap=new HashMap<Integer, Integer>();
		
		/* Drawing method
		 * */
		public void display(GLAutoDrawable arg0) {
			
			//Take the gl elemnt
			GL2ES2 gl=(GL2ES2)arg0.getGL();
			
			gl.getGL2ES2();
			//Clear the image
			gl.glClearColor(1, 1, 1, 1);
			
			gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
			
			gl.glEnable(GL.GL_DEPTH_TEST);
			gl.glEnable(GL.GL_TEXTURE_2D);
			
			gl.glUseProgram(shader.getShadingProgram());
			
			gl.glUniform4f(uniformColor, 1f, 1f, 1f, 1);
			float scaleFactor=0.025f;
			//t+=0.01f;
			float cos=(float)(Math.cos(-Math.PI/2+t));
			float sin=(float)(Math.sin(-Math.PI/2+t));
			
			
			float[][] scale={
					{scaleFactor,             0,    0,     0},
					{0,   scaleFactor,                   0,     0},
					{0,             0,     scaleFactor,     0},
					{0,0,0,1}
			};
			
			float[][] rotx={
					{1,             0,    0,     0},
					{0,   cos,                   -sin,     0},
					{0,             sin,     cos,     0},
					{0,0,0,1}
			};
			float cos2=(float)(Math.cos(Math.PI+t1));
			float sin2=(float)(Math.sin(-Math.PI+t1));
			float[][] roty={
					{cos2,             0,    sin2,     0},
					{0,   1,                   0,     0},
					{-sin2,             0,    cos2,     0},
					{0,0,0,1}
			};
			
			float[][] r1=ArrayUtils.matrixProduct(scale, rotx);
			r1=ArrayUtils.matrixProduct(roty, r1);
			
			nodo.setTransformMatrix(ArrayUtils.fromMatToVec(r1));
			
			float[][] unaltroscale={
					{0.075f,             0,    0,     0},
					{0,   0.075f,                   0,     0},
					{0,             0,     0.075f,     0},
					{0,0,0,1}
			};
			float[][] matrix=new float[4][4];
			railTraj.getTransformMatrix(matrix, tt);
			
			float[][] rotVx={
					{1,             0,    0,     0},
					{0,   0,                   +1,     0},
					{0,             -1,    0,     0},
					{0,0,0,1}
			};
			float[][] rotVy={
					{0,             0,    1,     0},
					{0,   1,                  0,     0},
					{-1,             0,    0,     0},
					{0,0,0,1}
			};
			
			float[][] upy={
					{1,             0,    0,     0},
					{0,   1,                  0,     distanceRailTubes.getY()},
					{0,             0,    1,     0},
					{0,0,0,1}
			};
			/*
			
			float[][] finalVagone=ArrayUtils.matrixProduct(rotVx, unaltroscale);
			finalVagone=ArrayUtils.matrixProduct(rotVy, finalVagone);
			finalVagone=ArrayUtils.matrixProduct(upy, finalVagone);
			float[][] finalVagone1=ArrayUtils.matrixProduct(matrix, finalVagone);
			finalVagone1=ArrayUtils.matrixProduct(r1, finalVagone1);
			nodo2.setTransformMatrix(ArrayUtils.fromMatToVec(finalVagone1));
			*/
			nodo.drawNode(gl);
			//nodo2.drawNode(gl);
			tt-=0.1f;
			
		}
		

		public void dispose(GLAutoDrawable arg0) {
			// TODO Auto-generated method stub
			
		}

		/* init method
		 * */
		public void init(GLAutoDrawable arg0) {

			//Take the gl elemnt
			GL2ES2 gl=(GL2ES2)arg0.getGL();
			gl.getGL2ES2();
			shader=new Shader(fragmentShader, vertexShader);
			
			shader.compileShader(gl);
			
			//------- All this part should be done by the producer ----------- //
			
			FixedStepTessellation tess=new FixedStepTessellation(new HomogeneousTextureCoordinatesEvaluator());
			tess.setStep_u(0.11f);
			tess.setStep_v(0.05f);
			XMLBinarioDataReader dr=new XMLBinarioDataReader("classic.xml");
			//XMLBinarioDataReader dr=new XMLBinarioDataReader("magnetic.xml");
			OBJFileVertexReader vertexReader=new OBJFileVertexReader();
			
			
			ClassicRailProducer producer=new ClassicRailProducer(tess, dr, vertexReader);
			//MagneticRailProducer producer=new MagneticRailProducer(tess, dr, vertexReader);
			nodo=producer.getNode(gl);
			railTraj=producer.getRailTrajectory();
			distanceRailTubes=producer.getDistanceBetweenTubes();
			
/*
			VagoneDataReader textureReader=new XMLVagoneDataReader("trainModels/templateVagoneSpace.xml");
			IMultipleSurfaceControlPointsReader vertexReader2=new OBJControlPointsMultipleSurfacesReader();
			FixedStepTessellation tess2=new FixedStepTessellation(new BorderTextureCoordinateEvaluator());
			tess2.setStep_u(0.1f);
			tess2.setStep_v(0.1f);
			
			NodoProducer producer2=new ClassicCoachProducer(textureReader, vertexReader2, tess2);
			nodo2=producer2.getNode(gl);*/
			
			//-------- END PRODUCER PART------//
			
			normalsAttribObject=gl.glGetAttribLocation(shader.getShadingProgram(), "normal");
			
			attribObject=gl.glGetAttribLocation(shader.getShadingProgram(), "position");
			
			textureAttribObject=gl.glGetAttribLocation(shader.getShadingProgram(), "texcoord");
			
			uniformColor=gl.glGetUniformLocation(shader.getShadingProgram(), "color");
			
			uniformTransform=gl.glGetUniformLocation(shader.getShadingProgram(), "transform");
			
			textureTransform=gl.glGetUniformLocation(shader.getShadingProgram(), "textureTransform");
			
			int[] shaderAttribs={attribObject,normalsAttribObject,textureAttribObject,textureTransform, uniformTransform};
			
			
			nodo.setShaderAttributes(shaderAttribs);
			//nodo2.setShaderAttributes(shaderAttribs);
			
		}

		public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3, int arg4) {
		}
		public void keyTyped(KeyEvent e) {
			// TODO Auto-generated method stub
			
		}
		public void keyPressed(KeyEvent e) {
			if(e.getKeyCode()==KeyEvent.VK_UP){
				t+=0.03f;
			}
			if(e.getKeyCode()==KeyEvent.VK_DOWN){
				t-=0.03f;
			}
			if(e.getKeyCode()==KeyEvent.VK_A){
				tt+=0.03f;
			}
			if(e.getKeyCode()==KeyEvent.VK_Z){
				tt-=0.03f;
			}
			if(e.getKeyCode()==KeyEvent.VK_RIGHT){
				t1+=0.03f;
			}
			if(e.getKeyCode()==KeyEvent.VK_LEFT){
				t1-=0.03f;
			}

		}
		public void keyReleased(KeyEvent e) {
			// TODO Auto-generated method stub
			
		}


		
	}
}
	
	

